package com.dh.convert.utils;

import org.apache.commons.lang3.StringUtils;

import java.lang.reflect.Field;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.math.BigDecimal;
import java.math.BigInteger;
import java.sql.Time;
import java.sql.Timestamp;
import java.util.*;

public class ClassUtils {

	private static final Map<String, Class<?>> commonMap = new HashMap<String, Class<?>>();

	static {
		commonMap.put("boolean", Boolean.TYPE);
		commonMap.put("byte", Byte.TYPE);
		commonMap.put("char", Character.TYPE);
		commonMap.put("short", Short.TYPE);
		commonMap.put("int", Integer.TYPE);
		commonMap.put("long", Long.TYPE);
		commonMap.put("double", Double.TYPE);
		commonMap.put("float", Float.TYPE);
		commonMap.put("Boolean", Boolean.class);
		commonMap.put("Byte", Byte.class);
		commonMap.put("Char", Character.class);
		commonMap.put("Short", Short.class);
		commonMap.put("Integer", Integer.class);
		commonMap.put("Long", Long.class);
		commonMap.put("Double", Double.class);
		commonMap.put("Float", Float.class);
		commonMap.put("Void", Void.class);
		commonMap.put("void", Void.TYPE);
		commonMap.put("String", String.class);
		commonMap.put("BigDecimal", BigDecimal.class);
		commonMap.put("BigInteger", BigInteger.class);
		commonMap.put("Calendar", Calendar.class);
		commonMap.put("Date", Date.class);
		commonMap.put("Locale", Locale.class);
		commonMap.put("UUID", UUID.class);
		commonMap.put("Time", Time.class);
		commonMap.put("SqlDate", java.sql.Date.class);
		commonMap.put("Timestamp", Timestamp.class);
		commonMap.put("Object", Object.class);
	}

	private static final Set<Class<?>> numberSet = new HashSet<Class<?>>();

	static {
		numberSet.add(Short.TYPE);
		numberSet.add(Integer.TYPE);
		numberSet.add(Long.TYPE);
		numberSet.add(Double.TYPE);
		numberSet.add(Float.TYPE);
		numberSet.add(Short.class);
		numberSet.add(Integer.class);
		numberSet.add(Long.class);
		numberSet.add(Double.class);
		numberSet.add(Float.class);
		numberSet.add(BigDecimal.class);
		numberSet.add(BigInteger.class);
	}

	private static final Set<Class<?>> commonSet = new HashSet<Class<?>>();

	static {
		commonSet.addAll(numberSet);
		commonSet.add(Boolean.TYPE);
		commonSet.add(Byte.TYPE);
		commonSet.add(Character.TYPE);
		commonSet.add(Void.TYPE);
		commonSet.add(Boolean.class);
		commonSet.add(Byte.class);
		commonSet.add(Character.class);
		commonSet.add(Void.class);
		commonSet.add(String.class);
		commonSet.add(Calendar.class);
		commonSet.add(Date.class);
		commonSet.add(Locale.class);
		commonSet.add(UUID.class);
		commonSet.add(Time.class);
		commonSet.add(java.sql.Date.class);
		commonSet.add(Timestamp.class);
		commonSet.add(Object.class);
	}

	private static final Map<String, Class<?>> TypeClassMap = new HashMap<String, Class<?>>();

	static {
		TypeClassMap.putAll(commonMap);
		TypeClassMap.put("List", ArrayList.class);
		TypeClassMap.put("Map", HashMap.class);
		TypeClassMap.put("Set", HashSet.class);
	}

	public static boolean isTypeClass(String typeName) {
		return TypeClassMap.containsKey(typeName);
	}

	public static Class<?> getTypeClass(String typeName) {
		if (StringUtils.isBlank(typeName))
			return null;
		Class<?> cls = TypeClassMap.get(typeName);
		if (cls == null) {
			try {
				cls = Class.forName(typeName);
			} catch (ClassNotFoundException e) {
			}
		}
		return cls;
	}

	public static boolean isArrayOrColltion(Class<?> cls) {
		return cls.isArray() || isColltion(cls);
	}

	public static boolean isColltion(Class<?> cls) {
		return Collection.class.isAssignableFrom(cls);
	}

	public static boolean isMap(Class<?> cls) {
		return Map.class.isAssignableFrom(cls);
	}

	public static boolean isPrimitive(Class<?> cls) {
		return cls.isPrimitive();
	}

	public static boolean isCommon(Class<?> cls) {
		return commonSet.contains(cls);
	}

	public static boolean isNumber(Class<?> cls) {
		return numberSet.contains(cls);
	}

	public static Class<?> getListType(Field f) {
		if (isColltion(f.getType())) {
			Type t = f.getGenericType();
			if (t instanceof Class)
				return Object.class;
			ParameterizedType ListType = (ParameterizedType) f.getGenericType();
			return (Class<?>) ListType.getActualTypeArguments()[0];
		}
		return null;
	}

}
